package com.cpms.framework.redis.aspect;

import com.cpms.framework.common.enums.GlobalResponseResultEnum;
import com.cpms.framework.common.exception.BizException;
import com.cpms.framework.common.utils.CsStringUtil;
import com.cpms.framework.redis.annotations.RepeatSubmit;
import com.cpms.framework.redis.utils.CsLockAspectUtil;
import com.cpms.framework.redis.utils.CsRedisUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @description:
 * @author: gulang
 * @time: 2021/11/24 15:16
 */
@Aspect
@Configuration
public class RepeatSubmitAspect {
    private final Logger logger = LoggerFactory.getLogger(RepeatSubmitAspect.class);
    private static final String DEFAULT_LOCK_KEY_PREFIX = "repeatSubmitLock:";
    private static final String DEFAULT_FLAG = "default";
    @Pointcut("@annotation(com.cpms.framework.redis.annotations.RepeatSubmit)")
    public void repeatSubmitAspectPoint(){}

    @Around("repeatSubmitAspectPoint() && @annotation(repeatSubmit)")
    public Object handelAround(ProceedingJoinPoint point, RepeatSubmit repeatSubmit) throws Throwable{
        long expire = repeatSubmit.expire();
        String[] fields = repeatSubmit.fields();
        Map<String, Object> params = CsLockAspectUtil.getParams(point, fields);
        String prefixKey = repeatSubmit.prefixKey();
        if (DEFAULT_FLAG.equalsIgnoreCase(prefixKey)) {
            prefixKey = DEFAULT_LOCK_KEY_PREFIX;
        }
        String lockKey = CsLockAspectUtil.createLockKey(prefixKey, params, point);
        String requestId = UUID.randomUUID().toString();
        try{
            boolean isLock = CsRedisUtil.lock(lockKey, requestId, expire, TimeUnit.MILLISECONDS);
            if(!isLock){
                String msg = CsStringUtil.isBlank(repeatSubmit.tips()) ?
                        GlobalResponseResultEnum.REPEAT_SUBMIT_HANDLE_ERROR.getMessage() : repeatSubmit.tips();
                throw new BizException(GlobalResponseResultEnum.REPEAT_SUBMIT_HANDLE_ERROR.getCode(),msg);
            }
            return point.proceed();
        }finally {
            if(repeatSubmit.delLock()){
                if(!CsRedisUtil.delLock(lockKey,requestId)) {
                    logger.error("[RepeatSubmitAspect] delete lock fail,lockKey={},requestId={}",lockKey,requestId);
                }
            }
        }
    }
}
